/**
 * This file is Copyright © 2008 Software Craftsmen Limited. All Rights Reserved.
 */
package com.softwarecraftsmen.orogeny.filing;

import com.softwarecraftsmen.orogeny.filing.fileSystems.FileSystem;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import static com.softwarecraftsmen.orogeny.filing.Folder.fromFile;
import static com.softwarecraftsmen.orogeny.filing.fileSystems.AbstractFileSystem.CurrentFileSystem;
import static java.lang.String.format;
import static java.util.Arrays.asList;
import static java.util.Locale.UK;

public class RelativeDirectory implements Directory
{
	private List<Folder> folders;

	@NotNull
	public static RelativeDirectory relativeDirectory(final @NotNull Folder... folders)
	{
		return new RelativeDirectory((asList(folders)));
	}

	public RelativeDirectory(final @NotNull List<Folder> folders)
	{
		this.folders = folders;
	}

	@NotNull
	public AbsoluteDirectory makeAbsolute(final @NotNull AbsoluteDirectory root)
	{
		AbsoluteDirectory deeperAbsoluteDirectory = root;
		for (Folder folder : folders)
		{
			deeperAbsoluteDirectory = deeperAbsoluteDirectory.childSubDirectory(folder);
		}
		return deeperAbsoluteDirectory;
	}

	@NotNull
	public static RelativeDirectory relativeDirectory(final @NotNull FileSystem fileSystem, final @NotNull File directoryPath)
	{
		if (directoryPath.exists() && directoryPath.isFile())
		{
			throw new IllegalArgumentException(format(UK, "directoryPath %1$s is a file", directoryPath));
		}
		if (directoryPath.isAbsolute())
		{
			throw new IllegalArgumentException(format(UK, "directoryPath %1$s is absolute", directoryPath));
		}
		final List<Folder> folders = fromFile(fileSystem, directoryPath);
		if (folders.size() > 0 && folders.get(0).isRoot())
		{
			throw new IllegalArgumentException(format(UK, "directoryPath %1$s is absolute", directoryPath));
		}
		return new RelativeDirectory(folders);
	}

	@NotNull
	public String toString()
	{
		return toFileSystemSpecificPath(CurrentFileSystem);
	}

	public boolean equals(final @Nullable Object o)
	{
		if (this == o)
		{
			return true;
		}
		if (o == null || getClass() != o.getClass())
		{
			return false;
		}

		final RelativeDirectory that = (RelativeDirectory) o;
		return folders.equals(that.folders);
	}

	public int hashCode()
	{
		return folders.hashCode();
	}

	@NotNull
	public String toFileSystemSpecificPathPrefixedByPathSeparator(final @NotNull FileSystem fileSystem)
	{
		return fileSystem.toFileSystemSpecificPathPrefixedByPathSeparator(folders);
	}

	@NotNull
	public String toFileSystemSpecificPathPrefixedByPathSeparator(final @NotNull FileSystem fileSystem, final @NotNull String fileName)
	{
		return fileSystem.toFileSystemSpecificPathPrefixedByPathSeparator(folders, fileName);
	}

	@NotNull
	public String toFileSystemSpecificPathPostfixedByFolderSeparator(final @NotNull FileSystem fileSystem)
	{
		return fileSystem.toFileSystemSpecificPathPostfixedByFolderSeparator(folders);
	}

	@NotNull
	public String toFileSystemSpecificPathPostfixedByPathSeparator(final @NotNull FileSystem fileSystem)
	{
		return fileSystem.toFileSystemSpecificPathPostfixedByPathSeparator(folders);
	}

	@NotNull
	public String toFileSystemSpecificPathPostfixedByPathSeparator(final @NotNull FileSystem fileSystem, final @NotNull String fileName)
	{
		return fileSystem.toFileSystemSpecificPathPostfixedByPathSeparator(folders, fileName);
	}

	@NotNull
	public String toFileSystemSpecificPath(final @NotNull FileSystem fileSystem)
	{
		return fileSystem.toFileSystemSpecificPath(folders);
	}

	@NotNull
	public String toFileSystemSpecificPath(final @NotNull FileSystem fileSystem, final @NotNull String fileName)
	{
		if (folders.isEmpty())
		{
			return fileName;
		}
		return fileSystem.toFileSystemSpecificPath(folders, fileName);
	}

	@NotNull
	public RelativeFile file(final @NotNull FileName fileName)
	{
		return new RelativeFile(this, fileName);
	}

	public boolean isEmpty()
	{
		return folders.isEmpty();
	}

	@NotNull
	public RelativeDirectory parent()
	{
		if (isEmpty())
		{
			return this;
		}
		else
		{
			return new RelativeDirectory(folders.subList(0, folders.size() - 1));
		}
	}

    @NotNull
    public RelativeDirectory subFolder(@NotNull final Folder folder)
    {
        final ArrayList<Folder> newFolders = new ArrayList<>(folders);
        newFolders.add(folder);
        return new RelativeDirectory(folders);
    }

	public boolean anyFolderIsHidden(final @NotNull AbsoluteDirectory root)
	{
		RelativeDirectory parent = this;
		while(!parent.isEmpty())
		{
			final AbsoluteDirectory absoluteDirectory = parent.makeAbsolute(root);
			if (absoluteDirectory.existsAndIsHidden())
			{
				return false;
			}
			parent = parent.parent();
		}
		return true;
	}

	@NotNull
	public String[] toFolders()
	{
		final String[] strings = new String[folders.size()];
		for(int index = 0; index < folders.size(); index++)
		{
			strings[index] = folders.get(index).toString();
		}
		return strings;
	}
}
